package com.gb.demand.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gb.demand.common.api.ResultMap;
import com.gb.demand.common.entity.Apilog;
import com.gb.demand.common.entity.Store;
import com.gb.demand.common.mapper.StoreMapper;
import com.gb.demand.service.IApilogService;
import com.gb.demand.service.IStoreService;
import com.gb.demand.service.ex.MyEx.AccessTokenException;
import com.gb.demand.util.DateUtil;
import com.gb.demand.util.JsonUtils;
import com.gb.demand.util.MD5Util;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Map;
import java.util.UUID;

/**
 * 用户业务层模块<p>
 *
 * @author wengjiangle
 * @since 2020/7/13
 */
@Slf4j
@Service
public class StoreServiceImpl extends ServiceImpl<StoreMapper, Store> implements IStoreService {

    @Autowired
    private IApilogService apilogService;

    /**
     * 新点获取接口令牌
     *
     * @param data
     * @return
     */
    @Override
    public Map getAccessToken(String data) {
        try {
            Map appinfoMap = JsonUtils.str2obj(data, Map.class);
            String appKey = String.valueOf(appinfoMap.get("appKey"));
            String appSecret = String.valueOf(appinfoMap.get("appSecret"));
            if (appKey.equals("") || appSecret.equals("")) {
                return ResultMap.generateResultMapwithKey("appkey或appsecret为空", false);
            }
            // 生成token令牌
            Store store = this.getOne(new LambdaQueryWrapper<Store>().eq(Store::getAppKey, appKey).eq(Store::getAppSecret, appSecret));
            if (store == null) {
                // 日志
                addApiLog(appKey, data, JsonUtils.obj2string(ResultMap.generateResultMap("", "没有找到对应appKey和appSecret的店铺", false)), "新点-获取接口令牌");
                // 生成没找到该店铺的Map
                return ResultMap.generateResultMap("", "没有找到对应appKey和appSecret的店铺", false);
            } else {
                this.createAccessToken(store);
                // 日志
                addApiLog(appKey, data, JsonUtils.obj2string(ResultMap.generateResultMap(store.getAccessToken(), "生成Token", true)), "新点-获取接口令牌");
                // 生成返回的Map
                return ResultMap.generateResultMap(store.getAccessToken(), "生成Token", true);
            }
        } catch (Exception e) {
            e.printStackTrace();
            //日志
            addApiLog("", data, JsonUtils.obj2string(ResultMap.generateResultMap("", e.getMessage(), false)), "新点-获取接口令牌");
            return ResultMap.generateResultMap("", e.getMessage(), false);
        }
    }

    /**
     * 判断token是否过期
     *
     * @param appKey
     * @param accessToken
     * @return
     */
    @Override
    public boolean checkAccessToken(String appKey, String accessToken) {
        Store store = new Store().selectOne(new LambdaQueryWrapper<Store>().eq(Store::getAppKey, appKey));
        if (store != null) {//找到了当前店铺
            if (store.getAccessToken() != null && !"".equals(store.getAccessToken())) {//不为空才能判断token是否过期
                // Token已存在，判断是否过期
                if (store.getAccessToken().equals(accessToken)) {
                    Date creTT = store.getCreateTokenTime();//上一次创建token的时间
                    Calendar creTTcalendar = Calendar.getInstance();
                    Calendar nowcalendar = Calendar.getInstance();
                    creTTcalendar.setTime(creTT);
                    nowcalendar.setTime(new Date());//当前时间
                    Long creTTMillis = creTTcalendar.getTimeInMillis();//毫秒数
                    Long nowMillis = nowcalendar.getTimeInMillis();//毫秒数
                    if ((nowMillis - creTTMillis) > 86400000L) {//如果2个时间之间超过了24小时
                        return false;//token没过期
                    } else {
                        return true;//token过期了

                    }
                } else {
                    throw new AccessTokenException("token输入有误，请重检查token");
                }
            } else {
                throw new AccessTokenException("token为空，请重新获取token");
            }
        } else {
            throw new AccessTokenException("没找到该appKey所对应的店铺");
        }
    }

    /**
     * 公采云判断token是否过期
     *
     * @param token
     * @return
     */
    @Override
    public boolean checkGcyAccessToken(String token) {
        Store store = new Store().selectOne(new LambdaQueryWrapper<Store>().eq(Store::getAccessToken, token));
        if (store != null) {//找到了当前店铺
            if (store.getAccessToken() != null && !"".equals(store.getAccessToken())) {//不为空才能判断token是否过期
                // Token已存在，判断是否过期
                if (store.getAccessToken().equals(token)) {
                    Date creTT = store.getCreateTokenTime();//上一次创建token的时间
                    Calendar creTTcalendar = Calendar.getInstance();
                    Calendar nowcalendar = Calendar.getInstance();
                    creTTcalendar.setTime(creTT);
                    nowcalendar.setTime(new Date());//当前时间
                    Long creTTMillis = creTTcalendar.getTimeInMillis();//毫秒数
                    Long nowMillis = nowcalendar.getTimeInMillis();//毫秒数
                    if ((nowMillis - creTTMillis) > 43200000L) {//如果2个时间之间超过了12小时
                        return false;//token没过期
                    } else {
                        return true;//token过期了

                    }
                } else {
                    throw new AccessTokenException("token输入有误，请重检查token");
                }
            } else {
                throw new AccessTokenException("token为空，请重新获取token");
            }
        } else {
            throw new AccessTokenException("没找到该appKey所对应的店铺");
        }
    }

    /**
     * 公采云授权获取Access Token
     * @param data
     * @return
     */
    @Override
    public Map authAccessToken(String data) {
        try {
            Map appinfoMap = JsonUtils.str2obj(data, Map.class);
            String timestamp = String.valueOf(appinfoMap.get("timestamp"));
            String username = String.valueOf(appinfoMap.get("username"));
            String password = String.valueOf(appinfoMap.get("password"));
            String sign = String.valueOf(appinfoMap.get("sign"));
            //验证签名是否正确
            String signs = username + password + timestamp + password;
            if(!sign.equals(MD5Util.md5(signs))){
                return ResultMap.gcyFaileResultMap("签名有误");
            }
            if (username.equals("") || password.equals("")) {
                return ResultMap.gcyFaileResultMap("username或password为空");
            }
            // 生成token令牌
            Store store = this.getOne(new LambdaQueryWrapper<Store>().eq(Store::getAppKey, username).eq(Store::getAppSecret, password));
            if (store == null) {
                // 日志
                addApiLog(username, data, JsonUtils.obj2string(ResultMap.generateResultMap("", "没有找到对应username和apassword的店铺", false)), "公采云-获取接口令牌");
                // 生成没找到该店铺的Map
                return ResultMap.gcyFaileResultMap("没有找到对应username和apassword的店铺");
            } else {
                this.createGcyAccessToken(store);
                String aftertime = DateUtil.aftertime(store.getCreateTokenTime());
                // 日志
                addApiLog(username, data, JsonUtils.obj2string(ResultMap.gcySucceedResultMap(store.getAccessToken(),aftertime)), "公采云-获取接口令牌");
                // 生成返回的Map
                return ResultMap.gcySucceedResultMap(store.getAccessToken(),aftertime);
            }
        } catch (Exception e) {
            e.printStackTrace();
            //日志
            addApiLog("", data, JsonUtils.obj2string(ResultMap.gcyFaileResultMap(e.getMessage())), "公采云-获取接口令牌");
            return ResultMap.gcyFaileResultMap(e.getMessage());
        }
    }

    /**
     * 日志记录
     *
     * @param caller      调用者
     * @param inputvalue  输入参数
     * @param outputvalue 输出参数
     * @param remark      备注
     */
    private void addApiLog(String caller, String inputvalue, String outputvalue, String remark) {
        // 记录调用日志
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        Apilog apilog = new Apilog(new Date(), false, "", request.getRequestURL().toString(), caller, inputvalue, outputvalue, remark);
        apilogService.save(apilog);
    }


    /**
     * 使用uuid创建token
     *
     * @param store 需要创建token的store对象
     * @return
     */
    private Boolean createAccessToken(Store store) throws ParseException {
        Date createTokenTime = store.getCreateTokenTime();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String format = simpleDateFormat.format(new Date());
        Date newTime = simpleDateFormat.parse(format);
        Long i = newTime.getTime() - createTokenTime.getTime();
        double result = i * 1.0 / (1000 * 60 * 60);
        //如果小于24小时继续使用 大于24小时再生成一个并维护
        if (result <= 24) {
            return false;
        } else {
            String accessToken = UUID.randomUUID().toString();
            // 创建Token 并记录创建时间
            store.setAccessToken(accessToken);
            store.setCreateTokenTime(new Date());
            return this.updateById(store);
        }

    }

    /**
     * 使用uuid创建token
     *
     * @param store 需要创建token的store对象
     * @return
     */
    private Boolean createGcyAccessToken(Store store) throws ParseException {
        Date createTokenTime = store.getCreateTokenTime();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String format = simpleDateFormat.format(new Date());
        Date newTime = simpleDateFormat.parse(format);
        Long i = newTime.getTime() - createTokenTime.getTime();
        double result = i * 1.0 / (1000 * 60 * 60);
        //如果小于24小时继续使用 大于24小时再生成一个并维护
        if (result <= 12) {
            return false;
        } else {
            String accessToken = UUID.randomUUID().toString();
            // 创建Token 并记录创建时间
            store.setAccessToken(accessToken);
            store.setCreateTokenTime(new Date());
            return this.updateById(store);
        }

    }
}
